﻿package shooter 
{
	import away3d.materials.utils.HeightMapDataChannel;
	import exey.helpers.BitmapSlicer;
	import flash.display.BitmapData;
	import flash.events.EventDispatcher;
	import flash.geom.Vector3D;
	import render3d.CrossEngineObject3D;
	import render3d.interfaces.IRender3DAdapter;

	/**
	 * 3D Tile Level
	 * @author Exey Panteleev
	 */
	public class Level
	{	
		[Embed(source='../../assets/skybox.jpg')] static private const SKYBOX_CLASS:Class;
		static private const SKYBOX_BITMAP_DATA:BitmapData = new SKYBOX_CLASS().bitmapData;	
		
		[Embed(source='../../assets/grounds256.png')] static private const GROUNDS_256_CLASS:Class;
		static private const GROUNDS_256_BITMAP_DATA:BitmapData = new GROUNDS_256_CLASS().bitmapData;
		
		[Embed(source='../../assets/walls256.png')] static private const WALLS_256_CLASS:Class;
		static private const WALLS_256_BITMAP_DATA:BitmapData = new WALLS_256_CLASS().bitmapData;
		
		public var ground:CrossEngineObject3D;
		private var skybox:CrossEngineObject3D;
		private var render:IRender3DAdapter;
		
		private var _groundData:Array;
		private var _wallsData:Array;
		private var _tileSize:Number;
		
		public function Level( render:IRender3DAdapter, groundData:Array, wallsData:Array, tileSize:Number, wallsfirstGID:uint ) 
		{
			this.render = render;
			_tileSize = tileSize
			addSkybox();
			addGround(groundData);
			addWalls(wallsData, wallsfirstGID);
		}
		
		private function addSkybox():void 
		{
			var bitmapSlices:BitmapSlicer = new BitmapSlicer(SKYBOX_BITMAP_DATA, 512, 512)
			skybox = render.createSkybox(bitmapSlices.slices[4], bitmapSlices.slices[5], bitmapSlices.slices[6], bitmapSlices.slices[7], bitmapSlices.slices[0], bitmapSlices.slices[1]);
			render.addChild(skybox)
		}
		
		private function addGround(tileData:Array):void 
		{
			_groundData = tileData;
			
			// slice tile set image map
			var tileSetBitmap:BitmapSlicer = new BitmapSlicer(GROUNDS_256_BITMAP_DATA, 256, 256)
			
			// add ground planes
			var plane:CrossEngineObject3D;
			var texture:BitmapData;
			var tileId:uint;
			var numCols:int = tileData.length
			var numRows:int = tileData[0].length
			var c:uint;
			var r:uint;	
			for(c = 0; c < numCols; c++) {
				for (r = 0; r < numRows; r++) {
					tileId = tileData[r][c]
					if (tileId != 0) {
						texture = tileSetBitmap.slices[tileId - 1];
						plane = render.createPlane(texture, texture.width, texture.height, "ground");
						plane.setPosition(c*_tileSize, (r+render.GRID_Y_FIX)*_tileSize, 0)
						render.addChild(plane)
					}
				}
			}
		}
		
		private function addWalls(tileData:Array, firstGID:uint):void {
			_wallsData = tileData
			
			// slice tile set image map
			var tileSetBitmap:BitmapSlicer = new BitmapSlicer(WALLS_256_BITMAP_DATA, 256, 256)
			
			// add wall planes			
			var texture:BitmapData;
			var tileId:uint;
			var numCols:int = tileData.length
			var numRows:int = tileData[0].length
			var c:uint;
			var r:uint;	
			for(c = 0; c < numCols; c++) {
				for (r = 0; r < numRows; r++) {
					tileId = tileData[r][c]
					if (tileId != 0) {
						texture = tileSetBitmap.slices[tileId - firstGID];
						if (c > 0 && _groundData[c-1][r] > 0) 
							addWallAccordingGround((c - 0.5) * _tileSize, (r+render.GRID_Y_FIX) * _tileSize, 180, -90, texture)
						if (c < numCols && _groundData[c+1][r] > 0) 
							addWallAccordingGround((c + 0.5) * _tileSize, (r+render.GRID_Y_FIX) * _tileSize, 180, 90, texture)
						if (r > 0 && _groundData[c][r-1] > 0) 
							addWallAccordingGround(c * _tileSize, (r - 0.5+render.GRID_Y_FIX) * _tileSize, 180, 180, texture)
						if (r < numRows && _groundData[c][r+1] > 0) {
							addWallAccordingGround(c * _tileSize, (r + 0.5 + render.GRID_Y_FIX) * _tileSize, 180, 0, texture)
						}
					}
				}
			}			
		}
		
		private function addWallAccordingGround(x:Number, y:Number, rotationX:Number, rotationZ:Number, texture:BitmapData):void {
			var plane:CrossEngineObject3D = render.createPlane(texture, texture.width, texture.height, "wall");
			plane.setPosition(x, y, texture.height*0.5)
			plane.setRotation(rotationX, Vector3D.X_AXIS)	
			plane.setRotation(rotationZ, Vector3D.Z_AXIS)	
			render.addChild(plane)
		}
		
		public function checkCollisionX(gridX:Number, gridY:Number, rightShift:Number):Number {
			var c:int = int(gridX + rightShift);
			var r:int = int(gridY);
			// if Collision
			if (!_wallsData[c] || _wallsData[c][r] != 0 || _wallsData[c+1][r] != 0) {
				if (rightShift > 0) rightShift = c - 0.0001 - gridX;
				else rightShift = rightShift - (gridX + rightShift - int(gridX))
			}
			return rightShift;
		}
		
		public function checkCollisionY(gridX:Number, gridY:Number, forwardShift:Number):Number {
			var c:int = int(gridX);
			var r:int = int(gridY + forwardShift);
			if (!_wallsData[c] || _wallsData[c][r] != 0 || _wallsData[c][r+1] != 0) {
				if (forwardShift > 0) forwardShift = r - 0.0001 - gridY;
				else forwardShift = forwardShift - (gridY + forwardShift - int(gridY))
			}
			return forwardShift;
		}
		
		public function get tileSize():Number { return _tileSize; }
	}
}